#include "stdafx.h"

#include "hwinhandle.h"
#include "hwinexception.h"
#include "hwincontrol.h"
#include "hwincom.h"
#include "hwinimaging.h"

#pragma comment(lib,"Windowscodecs")


namespace harlinn
{
    namespace windows
    {


        // ----------------------------------------------------------------------
        // SystemHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT SystemHandle::~SystemHandle()
        {
            if( OwnsHandle() && (Value() != INVALID_HANDLE_VALUE) )
            {
                CloseHandle(HANDLE(Value()));
            }
        }


        // ----------------------------------------------------------------------
        // ModuleHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT ModuleHandle::ModuleHandle(HMODULE hModule, bool closeHandle)
            : Base( hModule, closeHandle)
        {
             
        }

        HWIN_EXPORT ModuleHandle::ModuleHandle(const wchar_t* theModuleName, DWORD flags)
        {
            CheckPointerNotNull(theModuleName);
            HMODULE hModule = LoadLibraryEx(theModuleName, nullptr,flags);
            if(!hModule)
            {
                ThrowLastOSError();
            }
            SetValue(hModule);
        }
        HWIN_EXPORT ModuleHandle::ModuleHandle(const String& theModuleName, DWORD flags)
        {
            HMODULE hModule = LoadLibraryEx(theModuleName.c_str(), nullptr,flags);
            if(!hModule)
            {
                ThrowLastOSError();
            }
            SetValue(hModule);
        }
        HWIN_EXPORT ModuleHandle::ModuleHandle(std::shared_ptr<String> theModuleName, DWORD flags)
        {
            CheckPointerNotNull(theModuleName);
            HMODULE hModule = LoadLibraryEx(theModuleName->c_str(), nullptr,flags);
            if(!hModule)
            {
                ThrowLastOSError();
            }
            SetValue(hModule);
        }

        HWIN_EXPORT ModuleHandle::~ModuleHandle()
        {
            if(OwnsHandle() && Value())
            {
                FreeLibrary(static_cast<HMODULE>( Value() ));
            }
        }

        HWIN_EXPORT std::shared_ptr<ModuleHandle> ModuleHandle::Current()
        {
            HMODULE hModule = GetModuleHandle(nullptr);
            if(!hModule)
            {
                ThrowLastOSError();
            }
            std::shared_ptr<ModuleHandle> result = std::make_shared<ModuleHandle>(hModule,false);
            return result;
        }

        HWIN_EXPORT String ModuleHandle::GetModuleFileName() const
        {
            if(GetHMODULE())
            {
                wchar_t buffer[512];
                String::size_type length = ::GetModuleFileNameW((HMODULE)Value(),buffer,512);
                if(length == 0)
                {
                    ThrowLastOSError();
                }
                String result(buffer,length);
                return result;
            }
            return String();
        }


        // ----------------------------------------------------------------------
        // GraphicsDeviceObjectHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT GraphicsDeviceObjectHandle::GraphicsDeviceObjectHandle(HGDIOBJ theHandle, bool closeHandle)
            : Base(theHandle, closeHandle)
        {
        }

        // ----------------------------------------------------------------------
        // BitmapHandle
        // ----------------------------------------------------------------------
        BitmapHandle::map_t BitmapHandle::map;
        HWIN_EXPORT void BitmapHandle::AddHandleToMap(HBITMAP hElement,BitmapHandle* theHandle)
        {
            auto it = map.find(hElement);
            if(it ==  map.end())
            {
                map.insert( map_t::value_type(hElement,theHandle));
            }
        }
        HWIN_EXPORT BitmapHandle* BitmapHandle::GetHandleFromMap(HBITMAP hElement)
        {
            auto it = map.find(hElement);
            if(it !=  map.end())
            {
                auto result = (*it).second;
                return result;
            }
            return nullptr;
        }

        HWIN_EXPORT void BitmapHandle::RemoveHandleFromMap(HBITMAP hElement)
        {
            map.erase(hElement);
        }


        HWIN_EXPORT BitmapHandle::BitmapHandle(HBITMAP theHandle, bool ownsHandle)
            : Base(theHandle, ownsHandle)
        {
        }

        HWIN_EXPORT BitmapHandle::BitmapHandle(int resourceId, int width, int height,DWORD flags)
        {
            HANDLE hBitmap = LoadImage(0,MAKEINTRESOURCE(resourceId),IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }

        HWIN_EXPORT BitmapHandle::BitmapHandle(const wchar_t* theBitmapName, int width, int height,DWORD flags)
        {
            CheckPointerNotNull(theBitmapName);
            HANDLE hBitmap = LoadImage(0,theBitmapName,IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }

        

        HWIN_EXPORT BitmapHandle::BitmapHandle(const String& theBitmapName, int width, int height,DWORD flags)
        {
            HANDLE hBitmap = LoadImage(0,theBitmapName.c_str(),IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }
        HWIN_EXPORT BitmapHandle::BitmapHandle(std::shared_ptr<String> theBitmapName, int width, int height,DWORD flags)
        {
            CheckPointerNotNull(theBitmapName);
            HANDLE hBitmap = LoadImage(0,theBitmapName->c_str(),IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }


        HWIN_EXPORT BitmapHandle::BitmapHandle(std::shared_ptr<ModuleHandle> theModule, int resourceId, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            HANDLE hBitmap = LoadImage(hInstance,MAKEINTRESOURCE(resourceId),IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }

        HWIN_EXPORT BitmapHandle::BitmapHandle(std::shared_ptr<ModuleHandle> theModule, const wchar_t* theBitmapName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            CheckPointerNotNull(theBitmapName);
            HANDLE hBitmap = LoadImage(hInstance,theBitmapName,IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }
        HWIN_EXPORT BitmapHandle::BitmapHandle(std::shared_ptr<ModuleHandle> theModule, const String& theBitmapName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            HANDLE hBitmap = LoadImage(hInstance,theBitmapName.c_str(),IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }
        HWIN_EXPORT BitmapHandle::BitmapHandle(std::shared_ptr<ModuleHandle> theModule, std::shared_ptr<String> theBitmapName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            CheckPointerNotNull(theBitmapName);
            HANDLE hBitmap = LoadImage(hInstance,theBitmapName->c_str(),IMAGE_ICON,width,height,flags);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }
            SetValue(hBitmap, flags & LR_SHARED? false:true);
            AddHandleToMap(GetHBITMAP(),this);
        }

        HWIN_EXPORT BitmapHandle::~BitmapHandle()
        {
            RemoveHandleFromMap(GetHBITMAP());
            if(OwnsHandle() && Value())
            {
                DeleteObject(static_cast<HBITMAP>( Value() ));
            }
        }


        HWIN_EXPORT std::shared_ptr<BitmapHandle> BitmapHandle::FromHandle(HBITMAP theHandle, bool ownsHandle)
        {
            BitmapHandle* existingBitmapHandle = GetHandleFromMap(theHandle);
            if(existingBitmapHandle)
            {
                return existingBitmapHandle->As<BitmapHandle>();
            }
            else
            {
                return std::make_shared<BitmapHandle>(theHandle, ownsHandle);
            }
        }


        HWIN_EXPORT SIZE BitmapHandle::Size() const
        {
            SIZE result = {0,};
            HBITMAP hBitmap = GetHBITMAP();
            if(hBitmap)
            {
                if(GetBitmapDimensionEx(hBitmap,&result) == FALSE)
                {
                    ThrowLastOSError();
                }
            }
            return result;
        }


        HWIN_EXPORT std::shared_ptr<BitmapHandle> BitmapHandle::LoadFromFile(const String& theFileMame)
        {
            using namespace harlinn::windows::imaging;

            auto factory = ImagingFactory::Create();
            auto decoder = factory.CreateDecoderFromFilename(theFileMame);
            auto frame = decoder.GetFrame(0);
            auto result = frame.AsBitmapHandle();
            return result;

        /*
            IWICImagingFactory *pIWICFactory = nullptr;
            IWICBitmapDecoder *pDecoder = nullptr;
            IWICBitmapFrameDecode *pFrame = nullptr;
            IWICBitmapSource *pBitmapSource = nullptr;
            IWICBitmapSource *pConvertedBitmapSource = nullptr;
            IWICFormatConverter *pConverter = nullptr;
            HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pIWICFactory));
            CheckHRESULT(hr);
            UnknownPtr<IWICImagingFactory> imagingFactory(pIWICFactory);

            hr = imagingFactory->CreateDecoderFromFilename(theFileMame.c_str(),NULL,GENERIC_READ,WICDecodeMetadataCacheOnDemand,&pDecoder);
            CheckHRESULT(hr);
            UnknownPtr<IWICBitmapDecoder> decoder(pDecoder);
            
            hr = decoder->GetFrame(0,&pFrame);
            CheckHRESULT(hr);
            UnknownPtr<IWICBitmapFrameDecode> frame(pFrame);

            hr = pFrame->QueryInterface(IID_IWICBitmapSource, reinterpret_cast<void **>(&pBitmapSource));
            CheckHRESULT(hr);
            UnknownPtr<IWICBitmapSource> bitmapSource(pBitmapSource);
            
            hr = imagingFactory->CreateFormatConverter(&pConverter);
            CheckHRESULT(hr);
            UnknownPtr<IWICFormatConverter> converter(pConverter);
            
            hr = converter->Initialize(pBitmapSource,GUID_WICPixelFormat32bppBGR,WICBitmapDitherTypeNone,NULL,0.f,WICBitmapPaletteTypeCustom);
            CheckHRESULT(hr);

            hr = converter->QueryInterface(IID_PPV_ARGS(&pConvertedBitmapSource));
            CheckHRESULT(hr);
            UnknownPtr<IWICBitmapSource> convertedBitmapSource(pConvertedBitmapSource);

            UINT width = 0;
            UINT height = 0;
            hr = convertedBitmapSource->GetSize(&width, &height);
            CheckHRESULT(hr);

            BITMAPINFO bminfo;
            memset(&bminfo, 0,sizeof(bminfo));
            bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
            bminfo.bmiHeader.biWidth = width;
            bminfo.bmiHeader.biHeight = -(LONG)height; //top-down DIB with origin in the upper-left corner
            bminfo.bmiHeader.biPlanes = 1;
            bminfo.bmiHeader.biBitCount = 32;
            bminfo.bmiHeader.biCompression  = BI_RGB;

            HDC hdcScreen = GetDC(NULL);
            if(!hdcScreen)
            {
                ThrowLastOSError();
            }

            BYTE *imageBits = NULL;

            HBITMAP hBitmap = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS,(void**)&imageBits, NULL, 0);
            ReleaseDC(NULL, hdcScreen);
            if(!hBitmap)
            {
                ThrowLastOSError();
            }

            UINT strideSize = width * 4;
            UINT imageByteCount = strideSize*height;
            hr = convertedBitmapSource->CopyPixels(NULL,strideSize,imageByteCount, imageBits);
            
            if (FAILED(hr))
            {
                DeleteObject(hBitmap);
                CheckHRESULT(hr);
            }

            auto result = std::make_shared<BitmapHandle>(hBitmap,true);
            return result;
            */

        }



        // ----------------------------------------------------------------------
        // IconHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Question = std::make_shared<IconHandle>(OIC_QUES);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::WinLogo = std::make_shared<IconHandle>(OIC_WINLOGO);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Warning = std::make_shared<IconHandle>(OIC_WARNING);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Error = std::make_shared<IconHandle>(OIC_ERROR);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Information = std::make_shared<IconHandle>(OIC_INFORMATION);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Shield = std::make_shared<IconHandle>(OIC_SHIELD);

        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Question16x16 = std::make_shared<IconHandle>(OIC_QUES,16,16);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::WinLogo16x16 = std::make_shared<IconHandle>(OIC_WINLOGO,16,16);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Warning16x16 = std::make_shared<IconHandle>(OIC_WARNING,16,16);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Error16x16 = std::make_shared<IconHandle>(OIC_ERROR,16,16);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Information16x16 = std::make_shared<IconHandle>(OIC_INFORMATION,16,16);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Shield16x16 = std::make_shared<IconHandle>(OIC_SHIELD,16,16);

        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Question24x24 = std::make_shared<IconHandle>(OIC_QUES,24,24);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::WinLogo24x24 = std::make_shared<IconHandle>(OIC_WINLOGO,24,24);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Warning24x24 = std::make_shared<IconHandle>(OIC_WARNING,24,24);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Error24x24 = std::make_shared<IconHandle>(OIC_ERROR,24,24);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Information24x24 = std::make_shared<IconHandle>(OIC_INFORMATION,24,24);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Shield24x24 = std::make_shared<IconHandle>(OIC_SHIELD,24,24);

        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Question32x32 = std::make_shared<IconHandle>(OIC_QUES,32,32);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::WinLogo32x32 = std::make_shared<IconHandle>(OIC_WINLOGO,32,32);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Warning32x32 = std::make_shared<IconHandle>(OIC_WARNING,32,32);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Error32x32 = std::make_shared<IconHandle>(OIC_ERROR,32,32);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Information32x32 = std::make_shared<IconHandle>(OIC_INFORMATION,32,32);
        HWIN_EXPORT std::shared_ptr<IconHandle> IconHandle::Shield32x32 = std::make_shared<IconHandle>(OIC_SHIELD,32,32);


        HWIN_EXPORT IconHandle::IconHandle(HICON hIcon, bool closeHandle)
            : Base(hIcon, closeHandle)
        {
        }


        HWIN_EXPORT IconHandle::IconHandle(int resourceId, int width, int height,DWORD flags)
        {
            HANDLE hIcon = LoadImage(0,MAKEINTRESOURCE(resourceId),IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
            
        }

        HWIN_EXPORT IconHandle::IconHandle(const wchar_t* theIconName, int width, int height,DWORD flags)
        {
            CheckPointerNotNull(theIconName);
            HANDLE hIcon = LoadImage(0,theIconName,IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
        }

        

        HWIN_EXPORT IconHandle::IconHandle(const String& theIconName, int width, int height,DWORD flags)
        {
            HANDLE hIcon = LoadImage(0,theIconName.c_str(),IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
        }
        HWIN_EXPORT IconHandle::IconHandle(std::shared_ptr<String> theIconName, int width, int height,DWORD flags)
        {
            CheckPointerNotNull(theIconName);
            HANDLE hIcon = LoadImage(0,theIconName->c_str(),IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
        }


        HWIN_EXPORT IconHandle::IconHandle(std::shared_ptr<ModuleHandle> theModule, int resourceId, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            HANDLE hIcon = LoadImage(hInstance,MAKEINTRESOURCE(resourceId),IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
        }

        HWIN_EXPORT IconHandle::IconHandle(std::shared_ptr<ModuleHandle> theModule, const wchar_t* theIconName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            CheckPointerNotNull(theIconName);
            HANDLE hIcon = LoadImage(hInstance,theIconName,IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
        }
        HWIN_EXPORT IconHandle::IconHandle(std::shared_ptr<ModuleHandle> theModule, const String& theIconName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            HANDLE hIcon = LoadImage(hInstance,theIconName.c_str(),IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
        }
        HWIN_EXPORT IconHandle::IconHandle(std::shared_ptr<ModuleHandle> theModule, std::shared_ptr<String> theIconName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            CheckPointerNotNull(theIconName);
            HANDLE hIcon = LoadImage(hInstance,theIconName->c_str(),IMAGE_ICON,width,height,flags);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            SetValue(hIcon, flags & LR_SHARED? false:true);
        }

        HWIN_EXPORT IconHandle::~IconHandle()
        {
            if(OwnsHandle() && Value())
            {
                DestroyIcon(static_cast<HICON>( Value() ));
            }
        }

        // ----------------------------------------------------------------------
        // CursorHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::Normal = std::make_shared<CursorHandle>(OCR_NORMAL);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::IBeam = std::make_shared<CursorHandle>(OCR_IBEAM);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::Wait = std::make_shared<CursorHandle>(OCR_WAIT);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::Cross = std::make_shared<CursorHandle>(OCR_CROSS);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::Up = std::make_shared<CursorHandle>(OCR_UP);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::Size = std::make_shared<CursorHandle>(OCR_SIZEALL);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::SizeNWSE = std::make_shared<CursorHandle>(OCR_SIZENWSE);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::SizeNESW = std::make_shared<CursorHandle>(OCR_SIZENESW);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::SizeWE = std::make_shared<CursorHandle>(OCR_SIZEWE);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::SizeNS = std::make_shared<CursorHandle>(OCR_SIZENS);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::No = std::make_shared<CursorHandle>(OCR_NO);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::Hand = std::make_shared<CursorHandle>(OCR_HAND);
        HWIN_EXPORT std::shared_ptr<CursorHandle> CursorHandle::AppStarting = std::make_shared<CursorHandle>(OCR_APPSTARTING);


        HWIN_EXPORT CursorHandle::CursorHandle(int resourceId, int width, int height,DWORD flags)
        {
            HANDLE hCursor = LoadImage(0,MAKEINTRESOURCE(resourceId),IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
            
        }

        HWIN_EXPORT CursorHandle::CursorHandle(const wchar_t* theCursorName, int width, int height,DWORD flags)
        {
            CheckPointerNotNull(theCursorName);
            HANDLE hCursor = LoadImage(0,theCursorName,IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
        }

        

        HWIN_EXPORT CursorHandle::CursorHandle(const String& theCursorName, int width, int height,DWORD flags)
        {
            HANDLE hCursor = LoadImage(0,theCursorName.c_str(),IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
        }
        HWIN_EXPORT CursorHandle::CursorHandle(std::shared_ptr<String> theCursorName, int width, int height,DWORD flags)
        {
            CheckPointerNotNull(theCursorName);
            HANDLE hCursor = LoadImage(0,theCursorName->c_str(),IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
        }


        HWIN_EXPORT CursorHandle::CursorHandle(std::shared_ptr<ModuleHandle> theModule, int resourceId, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            HANDLE hCursor = LoadImage(hInstance,MAKEINTRESOURCE(resourceId),IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
        }

        HWIN_EXPORT CursorHandle::CursorHandle(std::shared_ptr<ModuleHandle> theModule, const wchar_t* theCursorName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            CheckPointerNotNull(theCursorName);
            HANDLE hCursor = LoadImage(hInstance,theCursorName,IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
        }
        HWIN_EXPORT CursorHandle::CursorHandle(std::shared_ptr<ModuleHandle> theModule, const String& theCursorName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            HANDLE hCursor = LoadImage(hInstance,theCursorName.c_str(),IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
        }
        HWIN_EXPORT CursorHandle::CursorHandle(std::shared_ptr<ModuleHandle> theModule, std::shared_ptr<String> theCursorName, int width, int height,DWORD flags)
        {
            HINSTANCE hInstance = 0;
            if(theModule)
            {
                hInstance = static_cast<HINSTANCE>( theModule->Value() );
            }
            CheckPointerNotNull(theCursorName);
            HANDLE hCursor = LoadImage(hInstance,theCursorName->c_str(),IMAGE_CURSOR,width,height,flags);
            if(!hCursor)
            {
                ThrowLastOSError();
            }
            SetValue(hCursor, flags & LR_SHARED? false:true);
        }

        HWIN_EXPORT CursorHandle::~CursorHandle()
        {
            if(OwnsHandle() && Value())
            {
                DestroyCursor(static_cast<HICON>( Value() ));
            }
        }


        // ----------------------------------------------------------------------
        // Menu
        // ----------------------------------------------------------------------

        HWIN_EXPORT MenuHandle::MenuHandle(HMENU hMenu, bool ownsHandle)
            : Base(hMenu,ownsHandle)
        {
        }

        HWIN_EXPORT MenuHandle::~MenuHandle( )
        {
            HMENU hMenu = GetHMENU();
            if(OwnsHandle() && hMenu)
            {
                DestroyMenu(hMenu);
            }
        }


        HWIN_EXPORT MenuHandle& MenuHandle::AddStyle(DWORD style)
        {
            MENUINFO menuinfo = {sizeof(menuinfo),0};
            menuinfo.fMask = MIM_STYLE;
            GetMenuInfo(menuinfo);
            menuinfo.dwStyle |= style;
            SetMenuInfo(menuinfo);

            return *this;
        }




        HWIN_EXPORT MenuHandle& MenuHandle::AppendMenu(UINT uFlags,UINT_PTR uIDNewItem,const wchar_t* newItem)
        {
            if(::AppendMenu(GetHMENU(),uFlags,uIDNewItem,newItem) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT MenuHandle& MenuHandle::CheckMenuRadioItem(UINT idFirst,UINT idLast,UINT idCheck,UINT uFlags)
        {
            if(::CheckMenuRadioItem(GetHMENU(),idFirst,idLast,idCheck,uFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT MenuHandle& MenuHandle::DeleteMenu(UINT position,UINT uFlags)
        {
            if(::DeleteMenu(GetHMENU(),position,uFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT MenuHandle& MenuHandle::EnableMenuItem(UINT idOfItem, UINT enableFlags)
        {
            if(::EnableMenuItem(GetHMENU(),idOfItem, enableFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT void MenuHandle::EndMenu( )
        {
            if(::EndMenu( ) == FALSE)
            {
                ThrowLastOSError();
            }
        }

        HWIN_EXPORT long MenuHandle::GetCheckMarkDimensions()
        {
            return ::GetMenuCheckMarkDimensions();
        }

        HWIN_EXPORT UINT MenuHandle::GetMenuDefaultItem(bool byPosition, UINT flags)
        {
            UINT result = ::GetMenuDefaultItem(GetHMENU(),byPosition, flags);
            if( result == -1)
            {
                ThrowLastOSError();
            }
            return result;
        }


        HWIN_EXPORT const MenuHandle& MenuHandle::GetMenuInfo(LPMENUINFO lpcmi) const
        {
            if(::GetMenuInfo(GetHMENU(),lpcmi) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT const MenuHandle& MenuHandle::GetMenuInfo(MENUINFO& lpcmi) const
        {
            if(::GetMenuInfo(GetHMENU(),&lpcmi) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT std::shared_ptr<MENUINFO> MenuHandle::GetMenuInfo( ) const
        {
            MENUINFO menuinfo = {sizeof(MENUINFO),0,};
            if(::GetMenuInfo(GetHMENU(),&menuinfo) == FALSE)
            {
                ThrowLastOSError();
            }
            return std::make_shared<MENUINFO>(menuinfo);
        }


        HWIN_EXPORT int MenuHandle::GetMenuItemCount( ) const
        {
            int result = ::GetMenuItemCount( GetHMENU() );
            if(result == -1)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT UINT MenuHandle::GetMenuItemID(int menuItemPosition) const
        {
            UINT result = ::GetMenuItemID( GetHMENU(), menuItemPosition);
            if(result == -1)
            {
                ThrowLastOSError();
            }
            return result;
        }


        HWIN_EXPORT const MenuHandle& MenuHandle::GetMenuItemInfo(UINT utemIdOrPosition, bool byPosition,LPMENUITEMINFO lpmii) const
        {
            if(::GetMenuItemInfo(GetHMENU(),utemIdOrPosition,byPosition,lpmii) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT const MenuHandle& MenuHandle::GetMenuItemInfo(UINT utemIdOrPosition, bool byPosition,MENUITEMINFO& lpmii) const
        {
            if(::GetMenuItemInfo(GetHMENU(),utemIdOrPosition,byPosition,&lpmii) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT std::shared_ptr<MENUITEMINFO> MenuHandle::GetMenuItemInfo(UINT utemIdOrPosition, bool byPosition) const
        {
            MENUITEMINFO menuiteminfo = {sizeof(MENUITEMINFO),0};
            if(::GetMenuItemInfo(GetHMENU(),utemIdOrPosition,byPosition,&menuiteminfo) == FALSE)
            {
                ThrowLastOSError();
            }
            return std::make_shared<MENUITEMINFO>(menuiteminfo);
        }

        HWIN_EXPORT UINT MenuHandle::GetMenuState(UINT itemIdOrPosition,bool byPosition) const
        {
            UINT result = ::GetMenuState( GetHMENU(), itemIdOrPosition,byPosition?MF_BYPOSITION:MF_BYCOMMAND);
            if(result == -1)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT int MenuHandle::GetMenuStringLength(UINT itemIdOrPosition,bool byPosition) const
        {
            int result = ::GetMenuString( GetHMENU(), itemIdOrPosition,nullptr,0,byPosition?MF_BYPOSITION:MF_BYCOMMAND);
            return result;
        }
        HWIN_EXPORT int MenuHandle::GetMenuString(UINT itemIdOrPosition,LPTSTR lpString,int nMaxCount,bool byPosition) const
        {
            int result = ::GetMenuString( GetHMENU(), itemIdOrPosition,lpString,nMaxCount,byPosition?MF_BYPOSITION:MF_BYCOMMAND);
            return result;
        }
        HWIN_EXPORT std::shared_ptr<String> MenuHandle::GetMenuString(UINT itemIdOrPosition,bool byPosition) const
        {
            int length = GetMenuStringLength(itemIdOrPosition,byPosition);
            if(length)
            {
                std::shared_ptr<String> result = std::make_shared<String>(size_t(length),'\x0');
                ::GetMenuString( GetHMENU(), itemIdOrPosition,const_cast<wchar_t*>(result->c_str()),length,byPosition?MF_BYPOSITION:MF_BYCOMMAND);
                return result;
            }
            return std::shared_ptr<String>();
        }

        HWIN_EXPORT HMENU MenuHandle::GetSubMenu(int position) const
        {
            HMENU result = ::GetSubMenu( GetHMENU(), position);
            
            return result;
        }


        HWIN_EXPORT MenuHandle& MenuHandle::InsertMenu(UINT uPosition,UINT uFlags, UINT_PTR itemIdOrPosition,LPCTSTR lpNewItem)
        {
            if(::InsertMenu(GetHMENU(),uPosition,uFlags, itemIdOrPosition,lpNewItem) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT MenuHandle& MenuHandle::InsertMenuItem(UINT itemIdOrPosition,bool byPosition,LPCMENUITEMINFO lpmii)
        {
            if(::InsertMenuItem(GetHMENU(),itemIdOrPosition,byPosition,lpmii) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT MenuHandle& MenuHandle::InsertMenuItem(UINT itemIdOrPosition,bool byPosition,const MENUITEMINFO& lpmii)
        {
            if(::InsertMenuItem(GetHMENU(),itemIdOrPosition,byPosition,&lpmii) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT bool MenuHandle::IsMenu() const
        {
            return ::IsMenu(GetHMENU()) != FALSE;
        }

        HWIN_EXPORT std::shared_ptr<MenuHandle> MenuHandle::LoadMenu(LPCTSTR lpMenuName)
        {
            return LoadMenu(ModuleHandle::Current(),lpMenuName);
        }
        HWIN_EXPORT std::shared_ptr<MenuHandle> MenuHandle::LoadMenu(std::shared_ptr<ModuleHandle> module,LPCTSTR lpMenuName)
        {
            HINSTANCE hInstance = module->GetHMODULE();
            return LoadMenu(hInstance,lpMenuName);
        }
        HWIN_EXPORT std::shared_ptr<MenuHandle> MenuHandle::LoadMenu(HINSTANCE module,LPCTSTR lpMenuName)
        {
            HMENU hMenu = ::LoadMenu(module,lpMenuName);
            if(!hMenu)
            {
                ThrowLastOSError();
            }
            std::shared_ptr<MenuHandle> result = std::make_shared<MenuHandle>(hMenu,false);
            return result;
        }


        HWIN_EXPORT MenuHandle& MenuHandle::ModifyMenu(UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCTSTR lpNewItem)
        {
            if(::ModifyMenu(GetHMENU(),uPosition,uFlags,uIDNewItem,lpNewItem) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT MenuHandle& MenuHandle::RemoveMenu(UINT uPosition,UINT uFlags)
        {
            if(::RemoveMenu(GetHMENU(),uPosition,uFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT MenuHandle& MenuHandle::SetMenuDefaultItem(UINT itemIdOrPosition,bool byPosition)
        {
            if(::SetMenuDefaultItem(GetHMENU(),itemIdOrPosition,byPosition) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT MenuHandle& MenuHandle::SetMenuItemInfo(UINT uItem, BOOL fByPosition, LPMENUITEMINFO lpmii)
        {
            if(::SetMenuItemInfo(GetHMENU(),uItem, fByPosition, lpmii) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT MenuHandle& MenuHandle::SetMenuInfo(LPCMENUINFO lpcmi)
        {
            if(::SetMenuInfo(GetHMENU(),lpcmi) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT MenuHandle& MenuHandle::SetMenuInfo(const MENUINFO& lpcmi)
        {
            if(::SetMenuInfo(GetHMENU(),&lpcmi) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT MenuHandle& MenuHandle::SetMenuItemBitmaps(UINT itemIdOrPosition,bool byPosition,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked)
        {
            if(::SetMenuItemBitmaps(GetHMENU(),itemIdOrPosition,byPosition,hBitmapUnchecked,hBitmapChecked) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        // ----------------------------------------------------------------------
        // BrushHandle
        // ----------------------------------------------------------------------
        BrushHandle::map_t BrushHandle::map;
        HWIN_EXPORT void BrushHandle::AddHandleToMap(HBRUSH hElement,BrushHandle* theHandle)
        {
            auto it = map.find(hElement);
            if(it ==  map.end())
            {
                map.insert( map_t::value_type(hElement,theHandle));
            }
        }
        HWIN_EXPORT BrushHandle* BrushHandle::GetHandleFromMap(HBRUSH hElement)
        {
            auto it = map.find(hElement);
            if(it !=  map.end())
            {
                auto result = (*it).second;
                return result;
            }
            return nullptr;
        }

        HWIN_EXPORT void BrushHandle::RemoveHandleFromMap(HBRUSH hElement)
        {
            map.erase(hElement);
        }

        HWIN_EXPORT BrushHandle::BrushHandle(HBRUSH theHandle, bool ownsHandle )
            : Base(theHandle, ownsHandle)
        {
            if(theHandle)
            {
                AddHandleToMap(theHandle,this);
            }
        }

        HWIN_EXPORT BrushHandle::BrushHandle(const LOGBRUSH& theLogBrush)
            : Base(CreateBrushIndirect(&theLogBrush),true)
        {
            if(!GetHBRUSH())
            {
                ThrowLastOSError();
            }
            AddHandleToMap(GetHBRUSH(),this);
        }
        HWIN_EXPORT BrushHandle::BrushHandle(std::shared_ptr<const LOGBRUSH> theLogBrush)
            : Base(CreateBrushIndirect(theLogBrush.get()),true)
        {
            if(!GetHBRUSH())
            {
                ThrowLastOSError();
            }
            AddHandleToMap(GetHBRUSH(),this);
        }
        HWIN_EXPORT BrushHandle::BrushHandle(COLORREF color)
            : Base(CreateSolidBrush(color),true)
        {
            if(!GetHBRUSH())
            {
                ThrowLastOSError();
            }
            AddHandleToMap(GetHBRUSH(),this);
        }

        HWIN_EXPORT BrushHandle::BrushHandle(SysColor sysColor)
            : Base(GetSysColorBrush( int(sysColor)),false)
        {
            if(!GetHBRUSH())
            {
                ThrowLastOSError();
            }
            AddHandleToMap(GetHBRUSH(),this); // <-- This probably doesn't work as well as intended
        }


        HWIN_EXPORT BrushHandle::~BrushHandle( )
        {
            HBRUSH theHandle = GetHBRUSH();
            if(theHandle)
            {
                RemoveHandleFromMap(theHandle);
            }
            if(OwnsHandle() && theHandle)
            {
                DeleteObject(theHandle);
            }
        }


        // ----------------------------------------------------------------------
        // PenHandle
        // ----------------------------------------------------------------------
        PenHandle::map_t PenHandle::map;
        HWIN_EXPORT void PenHandle::AddHandleToMap(HPEN hElement,PenHandle* theHandle)
        {
            auto it = map.find(hElement);
            if(it ==  map.end())
            {
                map.insert( map_t::value_type(hElement,theHandle));
            }
        }
        HWIN_EXPORT PenHandle* PenHandle::GetHandleFromMap(HPEN hElement)
        {
            auto it = map.find(hElement);
            if(it !=  map.end())
            {
                auto result = (*it).second;
                return result;
            }
            return nullptr;
        }

        HWIN_EXPORT void PenHandle::RemoveHandleFromMap(HPEN hElement)
        {
            map.erase(hElement);
        }

        HWIN_EXPORT PenHandle::PenHandle(HPEN theHandle, bool ownsHandle )
            : Base(theHandle, ownsHandle)
        {
            if(theHandle)
            {
                AddHandleToMap(theHandle,this);
            }
        }

        HWIN_EXPORT PenHandle::~PenHandle( )
        {
            HPEN theHandle = GetHPEN();
            if(theHandle)
            {
                RemoveHandleFromMap(theHandle);
            }
            if(OwnsHandle() && theHandle)
            {
                DeleteObject(theHandle);
            }
        }


        // ----------------------------------------------------------------------
        // FontHandle
        // ----------------------------------------------------------------------
        FontHandle::map_t FontHandle::map;
        HWIN_EXPORT void FontHandle::AddHandleToMap(HFONT hElement,FontHandle* theHandle)
        {
            auto it = map.find(hElement);
            if(it ==  map.end())
            {
                map.insert( map_t::value_type(hElement,theHandle));
            }
        }
        HWIN_EXPORT FontHandle* FontHandle::GetHandleFromMap(HFONT hElement)
        {
            auto it = map.find(hElement);
            if(it !=  map.end())
            {
                auto result = (*it).second;
                return result;
            }
            return nullptr;
        }

        HWIN_EXPORT void FontHandle::RemoveHandleFromMap(HFONT hElement)
        {
            map.erase(hElement);
        }

        HWIN_EXPORT FontHandle::FontHandle(HFONT theHandle, bool ownsHandle )
            : Base(theHandle, ownsHandle)
        {
            if(theHandle)
            {
                AddHandleToMap(theHandle,this);
            }
        }

        HWIN_EXPORT FontHandle::~FontHandle( )
        {
            HFONT theHandle = GetHFONT();
            if(theHandle)
            {
                RemoveHandleFromMap(theHandle);
            }
            if(OwnsHandle() && theHandle)
            {
                DeleteObject(theHandle);
            }
        }


        // ----------------------------------------------------------------------
        // RegionHandle
        // ----------------------------------------------------------------------
        RegionHandle::map_t RegionHandle::map;
        HWIN_EXPORT void RegionHandle::AddHandleToMap(HRGN hElement,RegionHandle* theHandle)
        {
            auto it = map.find(hElement);
            if(it ==  map.end())
            {
                map.insert( map_t::value_type(hElement,theHandle));
            }
        }
        HWIN_EXPORT RegionHandle* RegionHandle::GetHandleFromMap(HRGN hElement)
        {
            auto it = map.find(hElement);
            if(it !=  map.end())
            {
                auto result = (*it).second;
                return result;
            }
            return nullptr;
        }

        HWIN_EXPORT void RegionHandle::RemoveHandleFromMap(HRGN hElement)
        {
            map.erase(hElement);
        }

        HWIN_EXPORT RegionHandle::RegionHandle(HRGN theHandle, bool ownsHandle )
            : Base(theHandle, ownsHandle)
        {
            if(theHandle)
            {
                AddHandleToMap(theHandle,this);
            }
        }

        HWIN_EXPORT RegionHandle::~RegionHandle( )
        {
            HRGN theHandle = GetHRGN();
            if(theHandle)
            {
                RemoveHandleFromMap(theHandle);
            }
            if(OwnsHandle() && theHandle)
            {
                DeleteObject(theHandle);
            }
        }


        // ----------------------------------------------------------------------
        // PaletteHandle
        // ----------------------------------------------------------------------
        PaletteHandle::map_t PaletteHandle::map;
        HWIN_EXPORT void PaletteHandle::AddHandleToMap(HPALETTE hElement,PaletteHandle* theHandle)
        {
            auto it = map.find(hElement);
            if(it ==  map.end())
            {
                map.insert( map_t::value_type(hElement,theHandle));
            }
        }
        HWIN_EXPORT PaletteHandle* PaletteHandle::GetHandleFromMap(HPALETTE hElement)
        {
            auto it = map.find(hElement);
            if(it !=  map.end())
            {
                auto result = (*it).second;
                return result;
            }
            return nullptr;
        }

        HWIN_EXPORT void PaletteHandle::RemoveHandleFromMap(HPALETTE hElement)
        {
            map.erase(hElement);
        }

        HWIN_EXPORT PaletteHandle::PaletteHandle(HPALETTE theHandle, bool ownsHandle )
            : Base(theHandle, ownsHandle)
        {
            if(theHandle)
            {
                AddHandleToMap(theHandle,this);
            }
        }

        HWIN_EXPORT PaletteHandle::~PaletteHandle( )
        {
            HPALETTE theHandle = GetHPALETTE();
            if(theHandle)
            {
                RemoveHandleFromMap(theHandle);
            }
            if(OwnsHandle() && theHandle)
            {
                DeleteObject(theHandle);
            }
        }


        // ----------------------------------------------------------------------
        // DeviceContextHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT DeviceContextHandle::DeviceContextHandle( )
            : Base(),originalPen(0),originalBrush(0),originalBitmap(0),originalFont(0)
        {
            
        }

        HWIN_EXPORT DeviceContextHandle::DeviceContextHandle(HDC theHandle, bool ownsHandle)
            : Base(theHandle, ownsHandle),originalPen(0),originalBrush(0),originalBitmap(0),originalFont(0)
        {}

        HWIN_EXPORT DeviceContextHandle::~DeviceContextHandle( )
        {
        }

        HWIN_EXPORT void DeviceContextHandle::SaveDefaultObjects()
        {
            HDC hDC = GetHDC();
            if(hDC)
            {
                originalPen = (HPEN)GetCurrentObject(GetHDC(),OBJ_PEN);
                originalBrush = (HBRUSH)GetCurrentObject(GetHDC(),OBJ_BRUSH);
                originalBitmap = (HBITMAP)GetCurrentObject(GetHDC(),OBJ_BITMAP);
                originalFont = (HFONT)GetCurrentObject(GetHDC(),OBJ_FONT);
            }
        }
        HWIN_EXPORT void DeviceContextHandle::RestoreDefaultObjects()
        {
            HDC hDC = GetHDC();
            if(hDC)
            {
                SelectObject(hDC,originalPen);
                SelectObject(hDC,originalBrush);
                SelectObject(hDC,originalBitmap);
                SelectObject(hDC,originalFont);
            }
        }

        HWIN_EXPORT std::shared_ptr<PenHandle> DeviceContextHandle::Pen() const
        {
            auto hObject = GetCurrentObject(GetHDC(),OBJ_PEN);
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = PenHandle::GetHandleFromMap((HPEN)hObject);
            if(ptr)
            {
                return ptr->As<PenHandle>();
            }
            return std::make_shared<PenHandle>((HPEN)hObject,false);
        }
        HWIN_EXPORT std::shared_ptr<PenHandle> DeviceContextHandle::SetPen(const std::shared_ptr<PenHandle>& newPen)
        {
            auto hObject = SelectObject(GetHDC(),newPen->GetHPEN());
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = PenHandle::GetHandleFromMap((HPEN)hObject);
            if(ptr)
            {
                return ptr->As<PenHandle>();
            }
            return std::make_shared<PenHandle>((HPEN)hObject,false);
        }

        HWIN_EXPORT std::shared_ptr<BrushHandle> DeviceContextHandle::Brush() const
        {
            auto hObject = GetCurrentObject(GetHDC(),OBJ_BRUSH);
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = BrushHandle::GetHandleFromMap((HBRUSH)hObject);
            if(ptr)
            {
                return ptr->As<BrushHandle>();
            }
            return std::make_shared<BrushHandle>((HBRUSH)hObject,false);
        }
        HWIN_EXPORT std::shared_ptr<BrushHandle> DeviceContextHandle::SetBrush(const std::shared_ptr<BrushHandle>& newBrush)
        {
            auto hObject = SelectObject(GetHDC(),newBrush->GetHBRUSH());
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = BrushHandle::GetHandleFromMap((HBRUSH)hObject);
            if(ptr)
            {
                return ptr->As<BrushHandle>();
            }
            return std::make_shared<BrushHandle>((HBRUSH)hObject,false);
        }

        HWIN_EXPORT std::shared_ptr<BitmapHandle> DeviceContextHandle::Bitmap() const
        {
            auto hObject = GetCurrentObject(GetHDC(),OBJ_BITMAP);
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = BitmapHandle::GetHandleFromMap((HBITMAP)hObject);
            if(ptr)
            {
                return ptr->As<BitmapHandle>();
            }
            return std::make_shared<BitmapHandle>((HBITMAP)hObject,false);
        }
        HWIN_EXPORT std::shared_ptr<BitmapHandle> DeviceContextHandle::SetBitmap(const std::shared_ptr<BitmapHandle>& newBitmap)
        {
            auto hObject = SelectObject(GetHDC(),newBitmap->GetHBITMAP());
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = BitmapHandle::GetHandleFromMap((HBITMAP)hObject);
            if(ptr)
            {
                return ptr->As<BitmapHandle>();
            }
            return std::make_shared<BitmapHandle>((HBITMAP)hObject,false);
        }

        HWIN_EXPORT std::shared_ptr<FontHandle> DeviceContextHandle::Font() const
        {
            auto hObject = GetCurrentObject(GetHDC(),OBJ_FONT);
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = FontHandle::GetHandleFromMap((HFONT)hObject);
            if(ptr)
            {
                return ptr->As<FontHandle>();
            }
            return std::make_shared<FontHandle>((HFONT)hObject,false);
        }
        HWIN_EXPORT std::shared_ptr<FontHandle> DeviceContextHandle::SetFont(const std::shared_ptr<FontHandle>& newFont)
        {
            auto hObject = SelectObject(GetHDC(),newFont->GetHFONT());
            if(!hObject)
            {
                ThrowLastOSError();
            }
            auto ptr = FontHandle::GetHandleFromMap((HFONT)hObject);
            if(ptr)
            {
                return ptr->As<FontHandle>();
            }
            return std::make_shared<FontHandle>((HFONT)hObject,false);
        }

        


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawCaption(std::shared_ptr<Control> control, const RECT& boundingRectangle, DrawCaptionOptions options)
        {
            CheckPointerNotNull(control);
            if(::DrawCaption(control->GetSafeHandle() ,GetHDC(),&boundingRectangle, UINT(options)) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawEdge(RECT& boundingRectangle, BorderStyle borderStyle, BorderFlags borderFlags )
        {
            if(::DrawEdge(GetHDC(),&boundingRectangle, UINT(borderStyle), UINT(borderFlags) ) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawFocusRect(RECT& boundingRectangle )
        {
            if(::DrawFocusRect(GetHDC(),&boundingRectangle ) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawCaptionFrameControl(DrawFrameControlCaptionPart part, RECT& boundingRectangle, DrawFrameControlOptions options)
        {
            UINT state = UINT(part) | UINT(options);
            if(::DrawFrameControl(GetHDC(),&boundingRectangle,UINT(DrawFrameControlType::Caption),state ) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawMenuBarFrameControl(DrawFrameControlMenuBarPart part, RECT& boundingRectangle, DrawFrameControlOptions options)
        {
            UINT state = UINT(part) | UINT(options);
            if(::DrawFrameControl(GetHDC(),&boundingRectangle,UINT(DrawFrameControlType::MenuBar),state ) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawScrollBarFrameControl(DrawFrameControlScrollBarPart part, RECT& boundingRectangle, DrawFrameControlOptions options)
        {
            UINT state = UINT(part) | UINT(options);
            if(::DrawFrameControl(GetHDC(),&boundingRectangle,UINT(DrawFrameControlType::ScrollBar),state ) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawButtonFrameControl(DrawFrameControlButtonOptions buttonOptions, RECT& boundingRectangle, DrawFrameControlOptions options)
        {
            UINT state = UINT(buttonOptions) | UINT(options);
            if(::DrawFrameControl(GetHDC(),&boundingRectangle,UINT(DrawFrameControlType::Button),state ) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPopupMenuFrameControl(DrawFrameControlPopupMenuPart part, RECT& boundingRectangle, DrawFrameControlOptions options)
        {
            UINT state = UINT(part) | UINT(options);
            if(::DrawFrameControl(GetHDC(),&boundingRectangle,UINT(DrawFrameControlType::PopupMenu),state ) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawState(const String& theText, int x,int y,int cx,int cy,DrawStateFlags flags)
        {
            UINT uiFlags = UINT(flags);

            if((uiFlags & DSS_PREFIXONLY) != 0)
            {
                uiFlags &= ~DSS_HIDEPREFIX;
            }
            if((uiFlags & (DSS_HIDEPREFIX | DSS_PREFIXONLY)) != 0)
            {
                uiFlags |= DST_PREFIXTEXT;
            }
            if((uiFlags & DST_PREFIXTEXT) == 0)
            {
                uiFlags |= DST_TEXT;
            }

            if(::DrawState(GetHDC(),nullptr,nullptr,LPARAM(theText.c_str()),WPARAM(theText.length()), x,y,cx,cy, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawState(const String& theText, int x,int y,DrawStateFlags flags)
        {
            UINT uiFlags = UINT(flags);

            if((uiFlags & DSS_PREFIXONLY) != 0)
            {
                uiFlags &= ~DSS_HIDEPREFIX;
            }
            if((uiFlags & (DSS_HIDEPREFIX | DSS_PREFIXONLY)) != 0)
            {
                uiFlags |= DST_PREFIXTEXT;
            }
            if((uiFlags & DST_PREFIXTEXT) == 0)
            {
                uiFlags |= DST_TEXT;
            }

            if(::DrawState(GetHDC(),nullptr,nullptr,LPARAM(theText.c_str()),WPARAM(theText.length()), x,y,0,0, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawState(std::shared_ptr<BrushHandle> brush, const String& theText, int x,int y,int cx,int cy,DrawStateFlags flags)
        {
            UINT uiFlags = UINT(flags);

            if((uiFlags & DSS_PREFIXONLY) != 0)
            {
                uiFlags &= ~DSS_HIDEPREFIX;
            }
            if((uiFlags & (DSS_HIDEPREFIX | DSS_PREFIXONLY)) != 0)
            {
                uiFlags |= DST_PREFIXTEXT;
            }
            if((uiFlags & DST_PREFIXTEXT) == 0)
            {
                uiFlags |= DST_TEXT;
            }

            HBRUSH hBrush = nullptr;
            if(brush)
            {
                hBrush = brush->GetHBRUSH();
            }

            if(::DrawState(GetHDC(),hBrush,nullptr,LPARAM(theText.c_str()),WPARAM(theText.length()), x,y,cx,cy, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle:: DrawState(std::shared_ptr<BrushHandle> brush, const String& theText, int x,int y,DrawStateFlags flags)
        {
            UINT uiFlags = UINT(flags);

            if((uiFlags & DSS_PREFIXONLY) != 0)
            {
                uiFlags &= ~DSS_HIDEPREFIX;
            }
            if((uiFlags & (DSS_HIDEPREFIX | DSS_PREFIXONLY)) != 0)
            {
                uiFlags |= DST_PREFIXTEXT;
            }
            if((uiFlags & DST_PREFIXTEXT) == 0)
            {
                uiFlags |= DST_TEXT;
            }
            HBRUSH hBrush = nullptr;
            if(brush)
            {
                hBrush = brush->GetHBRUSH();
            }

            if(::DrawState(GetHDC(),hBrush,nullptr,LPARAM(theText.c_str()),WPARAM(theText.length()), x,y,0,0, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawState(std::shared_ptr<BitmapHandle> bitmap, int x,int y,int cx,int cy,DrawStateFlags flags)
        {
            CheckPointerNotNull(bitmap);
            UINT uiFlags = UINT(flags);

            uiFlags |= DST_BITMAP;

            if(::DrawState(GetHDC(),nullptr,nullptr,LPARAM(bitmap->GetHBITMAP()),0, x,y,cx,cy, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawState(std::shared_ptr<BitmapHandle> bitmap, int x,int y,DrawStateFlags flags)
        {
            CheckPointerNotNull(bitmap);
            UINT uiFlags = UINT(flags);

            uiFlags |= DST_BITMAP;

            if(::DrawState(GetHDC(),nullptr,nullptr,LPARAM(bitmap->GetHBITMAP()),0, x,y,0,0, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawState(std::shared_ptr<IconHandle> icon, int x,int y,int cx,int cy,DrawStateFlags flags)
        {
            CheckPointerNotNull(icon);
            UINT uiFlags = UINT(flags);

            uiFlags |= DST_ICON;

            if(::DrawState(GetHDC(),nullptr,nullptr,LPARAM(icon->GetHICON()),0, x,y,cx,cy, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawState(std::shared_ptr<IconHandle> icon, int x,int y,DrawStateFlags flags)
        {
            CheckPointerNotNull(icon);
            UINT uiFlags = UINT(flags);

            uiFlags |= DST_ICON;

            if(::DrawState(GetHDC(),nullptr,nullptr,LPARAM(icon->GetHICON()),0, x,y,0,0, uiFlags) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT RegionType DeviceContextHandle::ExcludeUpdateRgn(std::shared_ptr<Control> control)
        {
            CheckPointerNotNull(control);
            int result = ::ExcludeUpdateRgn(GetHDC(),control->GetSafeHandle());
            if(result == ERROR)
            {
                ThrowLastOSError();
            }
            return RegionType(result);
        }
        HWIN_EXPORT void DeviceContextHandle::Flush()
        {
            if(GdiFlush() == FALSE)
            {
                if(GetLastError())
                {
                    ThrowLastOSError();
                }
            }
        }
        HWIN_EXPORT DWORD DeviceContextHandle::BatchLimit()
        {
            DWORD result = GdiGetBatchLimit();
            if(!result)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT DWORD DeviceContextHandle::SetBatchLimit(DWORD newBatchLimit)
        {
            DWORD result = GdiSetBatchLimit(newBatchLimit);
            if(!result)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT ColorRef DeviceContextHandle::BackgroundColor() const
        {
            ColorRef result = GetBkColor(GetHDC());
            return result;
        }
        HWIN_EXPORT ColorRef DeviceContextHandle::SetBackgroundColor(COLORREF color)
        {
            ColorRef result = SetBkColor(GetHDC(),color);
            if( result.Invalid())
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT harlinn::windows::BackgroundMixMode DeviceContextHandle::BackgroundMixMode() const
        {
            int result = GetBkMode(GetHDC());
            if(!result)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::BackgroundMixMode(result);
        }

        HWIN_EXPORT harlinn::windows::BackgroundMixMode DeviceContextHandle::SetBackgroundMixMode(harlinn::windows::BackgroundMixMode mixMode)
        {
            int mode = int(mixMode);
            int result = SetBkMode(GetHDC(),mode);
            if(!result)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::BackgroundMixMode(result);
        }

        HWIN_EXPORT BoundsAccumulationFlags DeviceContextHandle::BoundsRect(RECT& boundingRectangle) const
        {
            int result = GetBoundsRect(GetHDC(),&boundingRectangle,0);
            if(!result)
            {
                ThrowLastOSError();
            }
            return BoundsAccumulationFlags(result);
        }
        HWIN_EXPORT BoundsAccumulationFlags DeviceContextHandle::BoundsRect(RECT& boundingRectangle, bool clear)
        {
            int result = GetBoundsRect(GetHDC(),&boundingRectangle,clear?DCB_RESET:0);
            if(!result)
            {
                ThrowLastOSError();
            }
            return BoundsAccumulationFlags(result);
        }


        HWIN_EXPORT BoundsAccumulationFlags DeviceContextHandle::SetBoundsRect(const RECT& boundingRectangle, BoundsAccumulationFlags flags)
        {
            int iFlags = int(flags);
            int result = ::SetBoundsRect(GetHDC(),&boundingRectangle,iFlags);
            if(!result)
            {
                ThrowLastOSError();
            }
            return BoundsAccumulationFlags(result);
        }

        HWIN_EXPORT harlinn::windows::ForegroundMixMode DeviceContextHandle::ForegroundMixMode() const
        {
            int result = GetROP2(GetHDC());
            if(!result)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::ForegroundMixMode(result);
        }
        HWIN_EXPORT harlinn::windows::ForegroundMixMode DeviceContextHandle::SetForegroundMixMode(harlinn::windows::ForegroundMixMode mixMode)
        {
            int mode = int(mixMode);
            int result = SetROP2(GetHDC(),mode);
            if(!result)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::ForegroundMixMode(result);
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawGrayString(const String& theText,int X,int Y,int nWidth,int nHeight)
        {
            if(theText.length())
            {
                if(::GrayString(GetHDC(),nullptr,nullptr,LPARAM(theText.c_str()),int(theText.length()),X,Y,nWidth,nHeight) == 0)
                {
                    ThrowLastOSError();
                }
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawGrayString(std::shared_ptr<BrushHandle> brush,const String& theText,int X,int Y,int nWidth,int nHeight)
        {
            if(theText.length())
            {
                HBRUSH hBrush = nullptr;
                if(brush)
                {
                    hBrush = brush->GetHBRUSH();
                }
                if(::GrayString(GetHDC(),hBrush,nullptr,LPARAM(theText.c_str()),int(theText.length()),X,Y,nWidth,nHeight) == 0)
                {
                    ThrowLastOSError();
                }
            }
            return *this;
        }


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawDesktopWallPaper()
        {
            if(PaintDesktop(GetHDC()) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawChord(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect,int nXRadial1,int nYRadial1,int nXRadial2,int nYRadial2)
        {
            if(::Chord(GetHDC(),nLeftRect,nTopRect,nRightRect,nBottomRect,nXRadial1,nYRadial1,nXRadial2,nYRadial2) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawChord(const RECT& rectangle,const POINT& start,const POINT& end)
        {
            if(::Chord(GetHDC(),rectangle.left,rectangle.top,rectangle.right,rectangle.bottom,start.x,start.y,end.x,end.y) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawEllipse(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect)
        {
            if(::Ellipse(GetHDC(),nLeftRect,nTopRect,nRightRect,nBottomRect) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawEllipse(const RECT& rectangle)
        {
            if(::Ellipse(GetHDC(),rectangle.left,rectangle.top,rectangle.right,rectangle.bottom) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawFilledRectangle(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect, std::shared_ptr<BrushHandle> brush)
        {
            CheckPointerNotNull(brush);
            RECT rect = {nLeftRect,nTopRect,nRightRect,nBottomRect};
            if(::FillRect(GetHDC(),&rect,brush->GetHBRUSH()) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawFilledRectangle(const RECT& rectangle, std::shared_ptr<BrushHandle> brush)
        {
            CheckPointerNotNull(brush);
            if(::FillRect(GetHDC(),&rectangle,brush->GetHBRUSH()) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawFrameRectangle(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect, std::shared_ptr<BrushHandle> brush)
        {
            CheckPointerNotNull(brush);
            RECT rect = {nLeftRect,nTopRect,nRightRect,nBottomRect};
            if(::FrameRect(GetHDC(),&rect,brush->GetHBRUSH()) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawFrameRectangle(const RECT& rectangle, std::shared_ptr<BrushHandle> brush)
        {
            CheckPointerNotNull(brush);
            if(::FrameRect(GetHDC(),&rectangle,brush->GetHBRUSH()) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawInvertedRectangle(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect)
        {
            RECT rect = {nLeftRect,nTopRect,nRightRect,nBottomRect};
            if(::InvertRect(GetHDC(),&rect) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawInvertedRectangle(const RECT& rectangle)
        {
            if(::InvertRect(GetHDC(),&rectangle) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPie(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect,int nXRadial1,int nYRadial1,int nXRadial2,int nYRadial2)
        {
            if(::Pie(GetHDC(),nLeftRect,nTopRect,nRightRect,nBottomRect,nXRadial1,nYRadial1,nXRadial2,nYRadial2) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPie(const RECT& rectangle,const POINT& start,const POINT& end)
        {
            if(::Pie(GetHDC(),rectangle.left,rectangle.top,rectangle.right,rectangle.bottom,start.x,start.y,end.x,end.y) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolygon(const POINT *lpPoints, int nCount)
        {
            if(::Polygon(GetHDC(),lpPoints, nCount) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolygon(const std::vector<POINT>& points)
        {
            if(::Polygon(GetHDC(),points.data(), int(points.size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolygon(std::shared_ptr<const std::vector<POINT> > polygon)
        {
            CheckPointerNotNull(polygon);
            if(::Polygon(GetHDC(),polygon->data(), int(polygon->size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyPolygons(const std::vector< std::vector<POINT> >& polyPolygons)
        {
            std::vector<INT> polyCounts;
            polyCounts.reserve(polyPolygons.size());
            size_t totalNumberOfPoints = 0;
            for ( auto polygon : polyPolygons)
            {
                if(polygon.size() < 2)
                {
                    throw ArgumentException("Not enough points in the polygon");
                }
                int numberOfPoints = INT(polygon.size());
                polyCounts.push_back(numberOfPoints);
                totalNumberOfPoints += numberOfPoints;
            }
            std::vector<POINT> points;
            points.reserve(totalNumberOfPoints);
            for ( auto polygon : polyPolygons)
            {
                for (auto point : polygon)
                {
                    points.push_back(point);
                }
            }
            if(::PolyPolygon(GetHDC(),points.data(),polyCounts.data(), int(polyCounts.size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyPolygon(const POINT *lpPoints,const INT *lpPolyCounts,int nCount)
        {
            if(::PolyPolygon(GetHDC(),lpPoints,lpPolyCounts,nCount) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawRectangle(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect)
        {
            if(::Rectangle(GetHDC(),nLeftRect,nTopRect,nRightRect,nBottomRect) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawRectangle(const RECT& rectangle)
        {
            if(::Rectangle(GetHDC(),rectangle.left,rectangle.top,rectangle.right,rectangle.bottom) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawRoundedRectangle(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect,int nWidth,int nHeight)
        {
            if(::RoundRect(GetHDC(),nLeftRect,nTopRect,nRightRect,nBottomRect,nWidth,nHeight) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawRoundedRectangle(const RECT& rectangle,int nWidth,int nHeight)
        {
            if(::RoundRect(GetHDC(),rectangle.left,rectangle.top,rectangle.right,rectangle.bottom,nWidth,nHeight) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawRoundedRectangle(const RECT& rectangle,const SIZE& ellipseSize)
        {
            if(::RoundRect(GetHDC(),rectangle.left,rectangle.top,rectangle.right,rectangle.bottom,ellipseSize.cx,ellipseSize.cy) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawAngleArc(int X,int Y,DWORD dwRadius,FLOAT eStartAngle,FLOAT eSweepAngle)
        {
            if(::AngleArc(GetHDC(),X,Y,dwRadius,eStartAngle,eSweepAngle) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawAngleArc(const POINT& center,DWORD dwRadius,FLOAT eStartAngle,FLOAT eSweepAngle)
        {
            if(::AngleArc(GetHDC(),center.x,center.y,dwRadius,eStartAngle,eSweepAngle) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawArc(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect,int nXStartArc,int nYStartArc,int nXEndArc,int nYEndArc)
        {
            if(::Arc(GetHDC(),nLeftRect,nTopRect,nRightRect,nBottomRect,nXStartArc,nYStartArc,nXEndArc,nYEndArc) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawArc(const RECT& rectangle,const POINT& start,const POINT& end)
        {
            if(::Arc(GetHDC(),rectangle.left,rectangle.top,rectangle.right,rectangle.bottom,start.x,start.y,end.x,end.y) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT harlinn::windows::ArcDirection DeviceContextHandle::ArcDirection() const
        {
            int result = GetArcDirection(GetHDC());
            if(!result)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::ArcDirection(result);
        }
        HWIN_EXPORT harlinn::windows::ArcDirection DeviceContextHandle::SetArcDirection(harlinn::windows::ArcDirection newArcDirection)
        {
            int nad = int(newArcDirection);
            int result = ::SetArcDirection(GetHDC(),nad);
            if(!result)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::ArcDirection(result);
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawLineTo(int nXEnd,int nYEnd)
        {
            if(::LineTo(GetHDC(),nXEnd,nYEnd) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawLineTo(const POINT& endPoint)
        {
            if(::LineTo(GetHDC(),endPoint.x,endPoint.y) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::MoveTo(int newX,int newY)
        {
            if(::MoveToEx(GetHDC(),newX,newY,nullptr) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::MoveTo(int newX,int newY, int& previousX, int& previousY )
        {
            POINT p = {0,};
            if(::MoveToEx(GetHDC(),newX,newY,&p) == FALSE)
            {
                ThrowLastOSError();
            }
            previousX = p.x;
            previousY = p.y;
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::MoveTo(const POINT& newPosition)
        {
            if(::MoveToEx(GetHDC(),newPosition.x,newPosition.y,nullptr) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::MoveTo(const POINT& newPosition, POINT& previousPosition)
        {
            if(::MoveToEx(GetHDC(),newPosition.x,newPosition.y,&previousPosition) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyBezier(const POINT *lppt,DWORD cPoints)
        {
            if(::PolyBezier(GetHDC(),lppt,cPoints) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyBezier(const std::vector<POINT>& points)
        {
            if(::PolyBezier(GetHDC(),points.data(),DWORD(points.size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyBezier(std::shared_ptr<const std::vector<POINT> > points)
        {
            CheckPointerNotNull(points);
            if(::PolyBezier(GetHDC(),points->data(),DWORD(points->size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyBezierTo(const POINT *lppt,DWORD cPoints)
        {
            if(::PolyBezierTo(GetHDC(),lppt,cPoints) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyBezierTo(const std::vector<POINT>& points)
        {
            if(::PolyBezierTo(GetHDC(),points.data(),DWORD(points.size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyBezierTo(std::shared_ptr<const std::vector<POINT> > points)
        {
            CheckPointerNotNull(points);
            if(::PolyBezier(GetHDC(),points->data(),DWORD(points->size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::Draw(const POINT *lppt,const PolyDrawCommand *lpbTypes,int cCount)
        {
            if(::PolyDraw(GetHDC(),lppt,(BYTE*)lpbTypes,cCount) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyLine(const POINT *lppt,DWORD cPoints)
        {
            if(::Polyline(GetHDC(),lppt,cPoints) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyLine(const std::vector<POINT>& points)
        {
            if(::Polyline(GetHDC(),points.data(),DWORD(points.size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyLine(std::shared_ptr<const std::vector<POINT> > points)
        {
            CheckPointerNotNull(points);
            if(::Polyline(GetHDC(),points->data(),DWORD(points->size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyLineTo(const POINT *lppt,DWORD cPoints)
        {
            if(::PolylineTo(GetHDC(),lppt,cPoints) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyLineTo(const std::vector<POINT>& points)
        {
            if(::PolylineTo(GetHDC(),points.data(),DWORD(points.size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT ColorRef DeviceContextHandle::TextColor() const
        {
            COLORREF resultClr = GetTextColor(GetHDC());
            if(resultClr == CLR_INVALID)
            {
                ThrowLastOSError();
            }
            return ColorRef(resultClr);
        }
        HWIN_EXPORT ColorRef DeviceContextHandle::SetTextColor(COLORREF colorRef)
        {
            COLORREF resultClr = ::SetTextColor(GetHDC(),colorRef);
            if(resultClr == CLR_INVALID)
            {
                ThrowLastOSError();
            }
            return ColorRef(resultClr);
        }


        HWIN_EXPORT harlinn::windows::TextAlignment DeviceContextHandle::TextAlignment() const
        {
            auto result = GetTextAlign(GetHDC());
            if(result == GDI_ERROR)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::TextAlignment(result);
        }
        HWIN_EXPORT harlinn::windows::TextAlignment DeviceContextHandle::SetTextAlignment(harlinn::windows::TextAlignment textAlignment)
        {
            UINT ta = UINT(textAlignment);
            auto result = SetTextAlign(GetHDC(),ta);
            if(result == GDI_ERROR)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::TextAlignment(result);
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawPolyLineTo(std::shared_ptr<const std::vector<POINT> > points)
        {
            CheckPointerNotNull(points);
            if(::PolylineTo(GetHDC(),points->data(),DWORD(points->size())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT int DeviceContextHandle::DrawText(const String& theText,RECT& rect, DrawTextFlags uFormat)
        {
            int result = ::DrawTextW(GetHDC(),theText.c_str(),int(theText.length()),&rect, UINT(uFormat));
            if(!result)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT int DeviceContextHandle::DrawText(LPCTSTR lpchText,int nCount,RECT& rect, DrawTextFlags uFormat)
        {
            int result = ::DrawTextW(GetHDC(),lpchText,nCount,&rect, UINT(uFormat));
            if(!result)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT int DeviceContextHandle::DrawText(LPWSTR lpchText,int nCount,RECT& rect, DrawTextFlags uFormat, DRAWTEXTPARAMS& drawTextParams)
        {
            int result = ::DrawTextExW(GetHDC(),lpchText,nCount,&rect, UINT(uFormat),&drawTextParams);
            if(!result)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawText(int nXStart,int nYStart,LPCTSTR lpString,int cchString)
        {
            if(::TextOutW(GetHDC(),nXStart,nYStart,lpString,cchString) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawText(int nXStart,int nYStart,const String& theText)
        {
            if(::TextOutW(GetHDC(),nXStart,nYStart,theText.c_str(),int(theText.length())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawText(const POINT& startPosition,const String& theText)
        {
            if(::TextOutW(GetHDC(),startPosition.x,startPosition.y,theText.c_str(),int(theText.length())) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT SIZE DeviceContextHandle::DrawText(int X, int Y,LPCTSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions, int nTabOrigin)
        {
            LONG res = ::TabbedTextOutW(GetHDC(),X, Y,lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin);
            if(!res)
            {
                ThrowLastOSError();
            }
            SIZE result = {LOWORD(res),HIWORD(res)};
            return result;
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawText(int X,int Y, UINT fuOptions, const RECT *lprc, LPCTSTR lpString, UINT cbCount, const INT *lpDx)
        {
            if(::ExtTextOutW(GetHDC(),X,Y, fuOptions, lprc, lpString, cbCount, lpDx) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT POINT DeviceContextHandle::CurrentPosition() const
        {
            POINT result = {0,};
            if(GetCurrentPositionEx(GetHDC(),&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT const DeviceContextHandle& DeviceContextHandle::CurrentPosition(POINT& currentPosition) const
        {
            if(GetCurrentPositionEx(GetHDC(),&currentPosition) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT harlinn::windows::GraphicsMode DeviceContextHandle::GraphicsMode() const
        {
            auto gm = GetGraphicsMode(GetHDC());
            if(!gm)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::GraphicsMode(gm);
        }

        HWIN_EXPORT harlinn::windows::GraphicsMode DeviceContextHandle::SetGraphicsMode(harlinn::windows::GraphicsMode newGraphicsMode)
        {
            auto gm = ::SetGraphicsMode(GetHDC(),int(newGraphicsMode));
            if(!gm)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::GraphicsMode(gm);
        }


        HWIN_EXPORT harlinn::windows::MapMode DeviceContextHandle::MapMode() const
        {
            auto mm = GetMapMode(GetHDC());
            if(!mm)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::MapMode(mm);
        }
        HWIN_EXPORT harlinn::windows::MapMode DeviceContextHandle::SetMapMode(harlinn::windows::MapMode newMapMode)
        {
            auto mm = ::SetMapMode(GetHDC(),int(newMapMode));
            if(!mm)
            {
                ThrowLastOSError();
            }
            return harlinn::windows::MapMode(mm);
        }

        HWIN_EXPORT SIZE DeviceContextHandle::ViewportExtent() const
        {
            SIZE result = {0,};
            if(GetViewportExtEx(GetHDC(),&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT SIZE DeviceContextHandle::SetViewportExtent(const SIZE& newViewportExtent )
        {
            SIZE result = {0,};
            if(SetViewportExtEx(GetHDC(),newViewportExtent.cx,newViewportExtent.cy,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT SIZE DeviceContextHandle::ScaleViewportExtent(int Xnum,int Xdenom,int Ynum,int Ydenom)
        {
            SIZE result = {0,};
            if(ScaleViewportExtEx(GetHDC(),Xnum,Xdenom,Ynum,Ydenom,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }


        HWIN_EXPORT POINT DeviceContextHandle::ViewportOrigin() const
        {
            POINT result = {0,};
            if(GetViewportOrgEx(GetHDC(),&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT POINT DeviceContextHandle::SetViewportOrigin(const POINT& newViewportOrigin)
        {
            POINT result = {0,};
            if(SetViewportOrgEx(GetHDC(),newViewportOrigin.x,newViewportOrigin.y,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT POINT DeviceContextHandle::OffsetViewportOrigin(int xOffset, int yOffset)
        {
            POINT result = {0,};
            if(OffsetViewportOrgEx(GetHDC(),xOffset, yOffset,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT SIZE DeviceContextHandle::WindowExtent() const
        {
            SIZE result = {0,};
            if(GetWindowExtEx(GetHDC(),&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT SIZE DeviceContextHandle::SetWindowExtent(const SIZE& newWindowExtent )
        {
            SIZE result = {0,};
            if(SetWindowExtEx(GetHDC(),newWindowExtent.cx,newWindowExtent.cy,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT SIZE DeviceContextHandle::ScaleWindowExtent(int Xnum,int Xdenom,int Ynum,int Ydenom)
        {
            SIZE result = {0,};
            if(ScaleWindowExtEx(GetHDC(),Xnum,Xdenom,Ynum,Ydenom,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }


        HWIN_EXPORT POINT DeviceContextHandle::WindowOrigin() const
        {
            POINT result = {0,};
            if(GetWindowOrgEx(GetHDC(),&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT POINT DeviceContextHandle::SetWindowOrigin(const POINT& newWindowOrigin)
        {
            POINT result = {0,};
            if(SetWindowOrgEx(GetHDC(),newWindowOrigin.x,newWindowOrigin.y,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT POINT DeviceContextHandle::OffsetWindowOrigin(int xOffset, int yOffset)
        {
            POINT result = {0,};
            if(OffsetWindowOrgEx(GetHDC(),xOffset, yOffset,&result) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }



        HWIN_EXPORT const DeviceContextHandle& DeviceContextHandle::WorldTransform(XFORM& xform) const
        {
            if(GetWorldTransform(GetHDC(),&xform) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT XFORM DeviceContextHandle::WorldTransform( ) const
        {
            XFORM xform;
            if(GetWorldTransform(GetHDC(),&xform) == FALSE)
            {
                ThrowLastOSError();
            }
            return xform;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::SetWorldTransform(XFORM& xform)
        {
            if(::SetWorldTransform(GetHDC(),&xform) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::ModifyWorldTransform(const XFORM& xform, bool rightMultiply)
        {
            if(::ModifyWorldTransform(GetHDC(),&xform,rightMultiply?MWT_RIGHTMULTIPLY:MWT_LEFTMULTIPLY) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::ResetWorldTransform( )
        {
            if(::ModifyWorldTransform(GetHDC(),nullptr,MWT_IDENTITY) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawBitmap(std::shared_ptr<BitmapHandle> bitmap)
        {
            POINT position = {0,};
            SIZE size = bitmap->Size();
            auto mdc = std::make_shared<MemoryDeviceContextHandle>(As<DeviceContextHandle>(),bitmap);
            
            
            return DrawBitmap(mdc,position,size);
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawBitmap(std::shared_ptr<BitmapHandle> bitmap, const POINT& position)
        {
            auto mdc = std::make_shared<MemoryDeviceContextHandle>(As<DeviceContextHandle>(),bitmap);
            SIZE size = bitmap->Size();
            return DrawBitmap(mdc,position,size);
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawBitmap(std::shared_ptr<BitmapHandle> bitmap, const POINT& position, const SIZE size)
        {
            auto mdc = std::make_shared<MemoryDeviceContextHandle>(As<DeviceContextHandle>(),bitmap);
            return DrawBitmap(mdc,position,size);
        }

        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawBitmap(std::shared_ptr<DeviceContextHandle> source)
        {
            auto size = source->ViewportExtent();
            POINT position = {0,};
            return DrawBitmap(source,position,size);
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawBitmap(std::shared_ptr<DeviceContextHandle> source, const POINT& position)
        {
            auto size = source->ViewportExtent();
            return DrawBitmap(source,position,size);
        }
        HWIN_EXPORT DeviceContextHandle& DeviceContextHandle::DrawBitmap(std::shared_ptr<DeviceContextHandle> source, const POINT& position, const SIZE size)
        {
            if(::BitBlt(GetHDC(), position.x, position.y, size.cx, size.cy, source->GetHDC(), 0, 0, SRCCOPY) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }


        // ----------------------------------------------------------------------
        // PaintDeviceContextHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT PaintDeviceContextHandle::PaintDeviceContextHandle(const std::shared_ptr<Control> theControl)
        {
            CheckPointerNotNull(theControl);
            windowHandle = theControl->GetSafeHandle();
            auto theHandle = BeginPaint(windowHandle,&paintStruct);
            if(!theHandle)
            {
                ThrowLastOSError();
            }
            SetValue(theHandle,true);
            SaveDefaultObjects();
        }
        HWIN_EXPORT PaintDeviceContextHandle::PaintDeviceContextHandle(HWND hWnd)
        {
            windowHandle = hWnd;
            auto theHandle = BeginPaint(windowHandle,&paintStruct);
            if(!theHandle)
            {
                ThrowLastOSError();
            }
            SetValue(theHandle,true);
            SaveDefaultObjects();
        }
        HWIN_EXPORT PaintDeviceContextHandle::~PaintDeviceContextHandle()
        {
            HDC hDC = GetHDC();
            if(hDC)
            {
                RestoreDefaultObjects();
            }
            if(OwnsHandle() && hDC)
            {
                EndPaint(windowHandle,&paintStruct);
            }
        }

        // ----------------------------------------------------------------------
        // MemoryDeviceContextHandle
        // ----------------------------------------------------------------------
        HWIN_EXPORT MemoryDeviceContextHandle::MemoryDeviceContextHandle(std::shared_ptr<DeviceContextHandle> deviceContext)
        {
            CheckPointerNotNull(deviceContext);
            HDC theHandle = CreateCompatibleDC(deviceContext->GetHDC());
            if(!theHandle)
            {
                ThrowLastOSError();
            }
            SetValue(theHandle,true);
            SaveDefaultObjects();
        }

        HWIN_EXPORT MemoryDeviceContextHandle::MemoryDeviceContextHandle(std::shared_ptr<DeviceContextHandle> deviceContext, std::shared_ptr<BitmapHandle> bitmap)
        {
            CheckPointerNotNull(deviceContext);
            CheckPointerNotNull(bitmap);

            HDC theHandle = CreateCompatibleDC(deviceContext->GetHDC());
            if(!theHandle)
            {
                ThrowLastOSError();
            }
            SetValue(theHandle,true);
            SaveDefaultObjects();

            SetBitmap(bitmap);

        }

        HWIN_EXPORT MemoryDeviceContextHandle::~MemoryDeviceContextHandle()
        {
            HDC hDC = GetHDC();
            if(hDC)
            {
                RestoreDefaultObjects();
            }
            if(OwnsHandle() && hDC)
            {
                DeleteDC(hDC);
            }
        }


    }
}